
#include "stack.h"
#include <ctype.h>
#include <string.h>
#include "cmds.h"

int main()
{
	FILE * prog = fopen( "program.txt", "r" );


	char command[50] = {0};
	int labels[16] = {0};

	for( int iter = 0, curIP = 0;
	        iter < 2;
	        iter++, curIP = 0 ) {
		FILE * code = fopen( "code.txt", "w" );

		while( fscanf( prog, " %s\n", command ) != -1 ) {

#define SET_CMD_(name)\
	if( strcmp(command, #name) == 0 ) {		\
		fprintf(code, "%d\n", CMD_##name);	\
		curIP++;							\
	} else

			SET_CMD_( NOP )
			SET_CMD_( RET )
			SET_CMD_( END )

			SET_CMD_( IN )
			SET_CMD_( OUT )

			SET_CMD_( SUM )
			SET_CMD_( SUB )
			SET_CMD_( MUL )
			SET_CMD_( DIV )
			SET_CMD_( POW )
			SET_CMD_( EXP )

#undef SET_CMD_

			if( strcmp( command, "PUSH" ) == 0 ) {
				stk_d arg = POISON;

				int chk = fscanf( prog, " %lg", &arg );

				if( chk == 1 ) {

					fprintf( code, "%d ", CMD_PUSH );
					fprintf( code, "%lg\n", arg );
					curIP += 2;

				} else if( chk == 0 ) {

					fprintf( code, "%d ", CMD_PUSHREG );
					curIP++;

					char arg_reg[5] = "EMTY";
					fscanf( prog, " %s", arg_reg );

#define SET_REG_(nam) 					\
	if( strcmp(#nam, arg_reg) == 0 ) {		\
		fprintf(code, "%d\n", REG_##nam);	\
		curIP++;							\
	} else

					SET_REG_( AX )
					SET_REG_( BX )
					SET_REG_( CX )
					SET_REG_( DX ) {
						DOUT( "Fatal error: unrecognized register to push from" );
						return CMD_ERR;
					}

#undef SET_REG_

				}
			} else if( strcmp( command, "POP" ) == 0 ) {
				char arg_reg[5] = "EMTY";
				int chk = fscanf( prog, " %s\n", arg_reg );

				if( chk == 0 ) {
					fprintf( code, "%d\n", CMD_POP );
					curIP++;
				} else if( chk == 1 ) {
					fprintf( code, "%d ", CMD_POPREG );
					curIP++;

#define SET_REG_(nam) 						\
	if( strcmp(#nam, arg_reg) == 0 ) {		\
		fprintf(code, "%d\n", REG_##nam);	\
		curIP++;							\
	} else

					SET_REG_( AX )
					SET_REG_( BX )
					SET_REG_( CX )
					SET_REG_( DX ) {
						DOUT( "Fatal error: unrecognized register to pop to" );
						return CMD_ERR;
					}

#undef SET_REG_

				}

			} else if( strcmp( command, "MOV" ) == 0 ) {
				char first_arg_reg[5] = "EMTY",
				                        secnd_arg_reg[5] = "EMTY";
				int chkf = fscanf( prog, " %s", first_arg_reg );

#define SET_REG_(nam, iden) 				\
	if( strcmp(#nam, iden##_arg_reg) == 0 ){\
		fprintf(code, " %d", REG_##nam);	\
		curIP++;							\
	} else

				stk_d mov_arg = POISON;
				int chks = fscanf( prog, " %lg\n", &mov_arg );

				if( chks == 0 ) {
					fprintf( code, "%d", CMD_MOVREG );
					curIP++;

					SET_REG_( AX, first )
					SET_REG_( BX, first )
					SET_REG_( CX, first )
					SET_REG_( DX, first ) {
						DOUT( "Fatal error: unrecognized register to mov to" );
						return CMD_ERR;
					}

					fscanf( prog, " %s", secnd_arg_reg );

					SET_REG_( AX, secnd )
					SET_REG_( BX, secnd )
					SET_REG_( CX, secnd )
					SET_REG_( DX, secnd ) {
						DOUT( "Fatal error: unrecognized register to mov from" );
						return CMD_ERR;
					}
					fprintf( code, "\n" );
				} else if( chks == 1 ) {
					fprintf( code, "%d", CMD_MOV );
					curIP++;

					SET_REG_( AX, first )
					SET_REG_( BX, first )
					SET_REG_( CX, first )
					SET_REG_( DX, first ) {
						DOUT( "Fatal error: unrecognized register to mov to" );
						return CMD_ERR;
					}

					fprintf( code, " %lg\n", mov_arg );
					curIP++;
				}

#undef SET_REG_

			} else if( command[0] == ':' ) {
				int labelarg = atoi( command + 1 );
				labels[labelarg] = curIP;
			} else if( strcmp( command, "CALL" ) == 0 ) {
				fprintf( code, "%d ", CMD_CALL );
				curIP++;

				int arg = 15;
				int chk = -1;

				chk = fscanf( prog, " %d", &arg );

				if( chk == 1 ) {
					fprintf( code, "%d\n", labels[arg] - 1 );
					curIP++;
				} else
					DOUT( "CALL didn't have a recognized argument" );
			} else if( strcmp( command, "JMP" ) == 0 ) {
				fprintf( code, "%d ", CMD_JMP );
				curIP++;

				int arg = 15;
				int chk = -1;

				chk = fscanf( prog, " %d", &arg );

				if( chk == 1 ) {
					fprintf( code, "%d\n", labels[arg] - 1 );
					curIP++;
				} else
					DOUT( "JMP didn't have a recognized argument" );
			} else if( strcmp( command, "JE" ) == 0 ) {
				fprintf( code, "%d ", CMD_JE );
				curIP++;

				int arg = 15;
				int chk = -1;

				chk = fscanf( prog, " %d", &arg );

				if( chk == 1 ) {
					fprintf( code, "%d\n", labels[arg] - 1 );
					curIP++;
				} else
					DOUT( "JE didn't have a recognized argument" );
			} else {
				DPUT( "Fatal error: unrecognized tokens detected at %d", curIP );
				return CMD_ERR;
			}


		}

		rewind( prog );
		fclose( code );
	}

	fclose( prog );
	DPUTCLOSURE;
	return 0;
}

